﻿using System;
using System.Xml;
using System.Xml.Linq;
using Xom.Elements;
using Xom.Engine;

namespace Xom
{
    public static class XmlObjectMapper
    {
        private static IXmlObjectMapper _mapper;

        /// <summary>
        /// Create a XOM Object from a Fle.
        /// </summary>
        /// <param name="filename">A URI string that references the file to load into a new XOM Object.</param>
        /// <param name="type">The type of the object that this XOM can serialize.</param>
        /// <returns>An XOM Object that contains the contents of the specified file.</returns>
        public static object Load(string filename, Type type)
        {
            _mapper = Create();
            return _mapper.Load(filename, type);
        }

        /// <summary>
        /// Create a XOM Object from a specified XDocument.
        /// </summary>
        /// <param name="xmlfile">A XDocument that references the file to load into a new XOM Object.</param>
        /// <param name="type">The type of the object that this XOM can serialize.</param>
        /// <returns>An XOM Object that contains the contents of the specified file.</returns>
        public static object Load(XDocument xmlfile, Type type)
        {
            _mapper = Create();
            return _mapper.Load(xmlfile, type);
        }

        /// <summary>
        /// Create a XOM Object from a specified XmlDocument.
        /// </summary>
        /// <param name="xmlnode">A XmlDocument that references the file to load into a new XOM Object.</param>
        /// <param name="type">The type of the object that this XOM can serialize.</param>
        /// <returns>An XOM Object that contains the contents of the specified file.</returns>
        public static object Load(XmlDocument xmlnode, Type type)
        {
            _mapper = Create();
            return _mapper.Load(xmlnode, type);
        }

        /// <summary>
        /// Save the loaded XML document to the specified file.
        /// </summary>
        /// <param name="filename">The location of the file where you want to save the document.</param>
        public static void Save(string filename)
        {
            _mapper.Save(filename);
        }

        /// <summary>
        /// Serialize the loaded XML document to a String.
        /// </summary>
        /// <returns>A String that the XML will be written to.</returns>
        public static string Save()
        {
            return _mapper.Save();
        }

        /// <summary>
        /// Creates a new XOM Object from a string.
        /// </summary>
        /// <param name="text">A string that contains XML.</param>
        /// <param name="type">The type of the object that this XOM can serialize.</param>
        /// <returns>An XOM Object populated from the string that contains XML.</returns>
        public static object Parse(string text, Type type)
        {
            _mapper = Create();
            return _mapper.Parse(text, type);
        }

        public static IXmlObjectMapper Create()
        {
            return new XmlObjectMapperContainer();
        }
    }

    public class XmlObjectMapperContainer : IXmlObjectMapper
    {
        private XmlDocumentEngine _xmlDocumentEngine = null;
        private XDocumentEngine _xDocumentEngine = null;

        /// <summary>
        /// Create a XOM Object from a Fle.
        /// </summary>
        /// <param name="filename">A URI string that references the file to load into a new XOM Object.</param>
        /// <param name="type">The type of the object that this XOM can serialize.</param>
        /// <returns>An XOM Object that contains the contents of the specified file.</returns>
        public object Load(string filename, Type type)
        {
            CreateXDocumentEngine();
            return _xDocumentEngine.Load(filename, type);
        }

        /// <summary>
        /// Create a XOM Object from a specified XDocument.
        /// </summary>
        /// <param name="xmlfile">A XDocument that references the file to load into a new XOM Object.</param>
        /// <param name="type">The type of the object that this XOM can serialize.</param>
        /// <returns>An XOM Object that contains the contents of the specified file.</returns>
        public object Load(XDocument xmlfile, Type type)
        {
            CreateXDocumentEngine();
            return _xDocumentEngine.Load(xmlfile, type);
        }

        /// <summary>
        /// Create a XOM Object from a specified XmlDocument.
        /// </summary>
        /// <param name="xmlnode">A XmlDocument that references the file to load into a new XOM Object.</param>
        /// <param name="type">The type of the object that this XOM can serialize.</param>
        /// <returns>An XOM Object that contains the contents of the specified file.</returns>
        public object Load(XmlNode xmlnode, Type type)
        {
            CreateXmlDocumentEngine();
            return _xmlDocumentEngine.StartMapping(xmlnode, type);
        }

        /// <summary>
        /// Save the loaded XML document to the specified file.
        /// </summary>
        /// <param name="filename">The location of the file where you want to save the document.</param>
        public void Save(string filename)
        {
            if (_xDocumentEngine != null) _xDocumentEngine.Save(filename);
        }

        /// <summary>
        /// Serialize the loaded XML document to a String.
        /// </summary>
        /// <returns>A String that the XML will be written to.</returns>
        public string Save()
        {
            if (_xDocumentEngine != null) return _xDocumentEngine.Save();

            return null;
        }

        /// <summary>
        /// Creates a new XOM Object from a string.
        /// </summary>
        /// <param name="text">A string that contains XML.</param>
        /// <param name="type">The type of the object that this XOM can serialize.</param>
        /// <returns>An XOM Object populated from the string that contains XML.</returns>
        public object Parse(string text, Type type)
        {
            CreateXDocumentEngine();
            return _xDocumentEngine.Parse(text, type);
        }

        /// <summary>
        /// Create a new XML document from a specified XOM Object.
        /// </summary>
        /// <param name="element">An XOM Object that contains the contents for the specified file.</param>
        /// <param name="filename">The location of the file where you want to save the document.</param>
        /// <param name="rootNodeName">The name of the root XML node.</param>
        public void Create(IXomElement element, string filename, string rootNodeName)
        {
            CreateXDocumentEngine();
            _xDocumentEngine.Create(element, filename, rootNodeName);
        }

        /// <summary>
        /// Create a new XDocument from a specified XOM Object.
        /// </summary>
        /// <param name="element">An XOM Object that contains the contents for the specified file.</param>
        /// <param name="rootNodeName">The name of the root XML node.</param>
        /// <returns>A XDocument that contains the contents of the specified XOM Object.</returns>
        public XDocument Create(IXomElement element, string rootNodeName)
        {
            CreateXDocumentEngine();
            return _xDocumentEngine.CreateDocument(element, rootNodeName);
        }

        /// <summary>
        /// Creates a new XElement from a specified Object
        /// </summary>
        /// <param name="element">An XOM Object that contains the contents for the new XElement.</param>
        /// <param name="rootNodeName">The name of the root XML node.</param>
        /// <returns>A XElement that contains the contents of the specified object</returns>
        public XElement CreateElement(IXomElement element, string rootNodeName)
        {
            CreateXDocumentEngine();
            return _xDocumentEngine.CreateElement(element, rootNodeName);
        }

        private void CreateXDocumentEngine()
        {
            _xDocumentEngine = new XDocumentEngine();
        }

        private void CreateXmlDocumentEngine()
        {
            _xmlDocumentEngine = new XmlDocumentEngine();
        }
    }
}
